using System;
using System.Collections.Generic;

namespace Space_Conquest
{

    enum AnimationType
    {
        TakeHit = 0,
        BuildHammer = 1,
        MoveTo = 2,
        AttackUnit = 3,
        GatherUnit = 4,
        BuildUnit = 5
    }

    enum RenderLayer
    {
        MapTiles,
        BelowGroundUnits,
        GroundUnits,
        AboveGroundUnitsBelowAirUnits,
        AirUnits,
        AboveAirUnits
    }

    class Animation :  IMotion
    {

        #region Private Members

        static List<Texture> _frames = new List<Texture>();
        static Sprite _sprite;

        AnimationType _type;
        Texture _frameMap;
        MapPoint _location;
        bool _isFinished;
        int _currentFrame;
        int _alpha;
        List<int> _frameOrder = new List<int>();


        #endregion

        #region Properties

        public bool IsFinished
        {
            get
            {
                return _isFinished;
            }
        }

        #endregion

        #region Constructors

        static Animation()
        {

            _sprite = new Sprite(0, 0, 64, 64);

            // Load all possible animation frames
            _frames.Add(new Texture("Images/AttackHit.bmp"));
            _frames.Add(new Texture("Images/BuildHammer.bmp"));
            _frames.Add(new Texture("Images/MoveTo.bmp"));
            _frames.Add(new Texture("Images/AttackUnit.bmp"));
            _frames.Add(new Texture("Images/GatherUnit.bmp"));
            _frames.Add(new Texture("Images/BuildUnit.bmp"));

        }

        public Animation(AnimationType type, MapPoint location)
        {

            _isFinished = false;
            _type = type;
            _location = location;
            _currentFrame = 0;
            _alpha = 255;

            switch (_type)
            {
                case AnimationType.TakeHit:
                    CreateFrameOrder(new int[] { 0, 0, 0, 1, 1, 1});
                    break;
                case AnimationType.BuildHammer:
                    CreateFrameOrder(new int[] { 0, 0, 1, 1, 2, 2 });
                    break;
                case AnimationType.MoveTo:
                    CreateFrameOrder(new int[] { 0, 0, 1, 1, 2, 2, 3, 3 });
                    _alpha = 150;
                    break;
                case AnimationType.AttackUnit:
                case AnimationType.GatherUnit:
                case AnimationType.BuildUnit:
                    CreateFrameOrder(new int[] { 0, 0, 1, 1, 0, 0, 1, 1, 2, 2, 3, 3, 2, 2, 3, 3 });
                    _alpha = 150;
                    break;
                default:
                    throw new Exception("Invalid animation type");
            }

            _frameMap = _frames[(int)_type];

        }

        void CreateFrameOrder(int[] frameOrder)
        {
            foreach (int frame in frameOrder)
            {
                _frameOrder.Add(frame);
            }
        }

        #endregion

        #region Methods

        #endregion

        #region IRender Members

        public void Render()
        {

            if (!_isFinished)
            {

                _sprite.Alpha = _alpha;

                _sprite.Left = _location.X * Globals.TILE_SIZE;
                _sprite.Top = _location.Y * Globals.TILE_SIZE;

                _sprite.Render(_frameMap, _frameOrder[_currentFrame]);

            }

        }

        #endregion

        #region IMotion Members

        public void Motion()
        {

            ++_currentFrame;

            if (_currentFrame > _frameOrder.Count - 1)
                _isFinished = true;

        }

        #endregion
    }

    /// <summary>
    /// Displays and manages animations. This is separate from any game logic. (just visuals to make game look better)
    /// </summary>
    class AnimationManager : IMotion
    {

        #region Private Members

        GameEngine _parent;

        List<Animation> _underGroundAnimations = new List<Animation>();
        List<Animation> _overGroundAnimations = new List<Animation>();
        List<Animation> _overAirAnimations = new List<Animation>();

        #endregion

        #region Properties

        public GameEngine Parent
        {
            get
            {
                return _parent;
            }
        }

        #endregion

        #region Constructors

        public AnimationManager(GameEngine parent)
        {

            _parent = parent;

        }

        #endregion

        #region Methods

        public void DisplayAnimation(AnimationType type, RenderLayer layer, MapPoint point)
        {

            if(Parent.Map.IsWithinRenderBounds(point) &&
               Parent.LocalPlayer.FogArray[point.X, point.Y] == FogStatus.Visible)
            {

                switch(layer)
                {
                    case RenderLayer.BelowGroundUnits:
                        _underGroundAnimations.Add(new Animation(type, point));
                        break;
                    case RenderLayer.AboveGroundUnitsBelowAirUnits:
                        _overGroundAnimations.Add(new Animation(type, point));
                        break;
                    case RenderLayer.AboveAirUnits:
                        _overAirAnimations.Add(new Animation(type, point));
                        break;
                    default:
                        throw new Exception("Invalid Layer to render animation on.");
                }

            }

        }

        #endregion

        #region IRender Members

        public void Render(RenderLayer layer)
        {

            List<Animation> renderList = null;

            switch (layer)
            {
                case RenderLayer.BelowGroundUnits:
                    renderList = _underGroundAnimations;
                    break;
                case RenderLayer.AboveGroundUnitsBelowAirUnits:
                    renderList = _overGroundAnimations;
                    break;
                case RenderLayer.AboveAirUnits:
                    renderList = _overAirAnimations;
                    break;
                default:
                    break;
            }

            if (renderList != null)
            {

                foreach (Animation anime in renderList)
                {

                    anime.Render();

                }

            }
        }

        #endregion

        #region IMotion Members

        public void Motion()
        {

            foreach (Animation anime in _underGroundAnimations)
                anime.Motion();

            foreach (Animation anime in _overGroundAnimations)
                anime.Motion();

            foreach (Animation anime in _overAirAnimations)
                anime.Motion();


            // Need to remove finished animations:

            foreach (List<Animation> list in new List<Animation>[] { _underGroundAnimations, _overGroundAnimations, _overAirAnimations })
            {

                List<Animation> remList = new List<Animation>();

                foreach (Animation anime in list)
                    if (anime.IsFinished)
                        remList.Add(anime);

                foreach (Animation anime in remList)
                    list.Remove(anime);

            }

        }

        #endregion
    
    }

}